package com.cxdr.awsips.packing.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

import com.cxdr.awsips.packing.bean.Target;
import com.cxdr.awsips.packing.config.SystemConfig;
import com.cxdr.awsips.packing.logger.LogFactory;
import com.cxdr.awsips.packing.net.FTPUtils;

public class FTPFileHelper implements FileHelper {
	private static Logger logger = LogFactory
			.makeNewLogger(FTPFileHelper.class);
	private FTPClient ftpClient;
	private Target target;
	private String HOME_WORK;
	private String localDir;
	private String remoteDir;
	private String remoteFileSeparator = "/";

	public FTPFileHelper(FTPClient ftpClient) {
		this.ftpClient = ftpClient;
	}

	public FTPFileHelper(Target target)
			throws IOException {
		this.target = target;
		setRemoteDir(target.getPath());
	}
	
	private void init(FTPClient ftpClient) {
		localDir = SystemConfig.get("path.source");
		if(StringUtils.isBlank(localDir)){
			localDir = System.getProperty("user.dir");
		}
		this.ftpClient = ftpClient;
		try {
			HOME_WORK = ftpClient.printWorkingDirectory();
			// 特定于类unix系统
			if (HOME_WORK.equals("/")) {
				HOME_WORK = "";
			}
			String ftpSystemType = ftpClient.getSystemType();
			logger.info(ftpSystemType);
			if (ftpSystemType.contains("UNIX")) {
				remoteFileSeparator = "/";
			} else {
				remoteFileSeparator = "\\";
			}
			if(StringUtils.isBlank(remoteDir)){
				remoteDir = ftpClient.printWorkingDirectory();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void open() throws IOException {
		init(FTPUtils.loginFtp(target.getIp(),target.getUsername(),target.getPassword()));
	}
	public void close() {
		FTPClient ftp = getFtpClient();
		if (ftp != null && ftp.isConnected()) {
			try {
				ftp.logout();
				ftp.disconnect();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void getDir(String dir) {
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return;
		}
		if (!(dir == null || dir.length() == 0)) {
			try {
				Set<String> remoteFileNames = new TreeSet<String>();
				if (ftp.cwd(dir) == FTPReply.FILE_ACTION_OK) {
					FTPFile[] ftpFiles = ftp.listFiles();
					for (FTPFile ftpFile : ftpFiles) {
						if (ftpFile.isFile()
								&& ftpFile.getName().contains("txt")) {
							remoteFileNames.add(ftpFile.getName());
						}
					}
				}
				File localDir = new File(getLocalDir() + File.separator + dir);
				if (!localDir.exists()) {
					localDir.mkdirs();
				}
				// logger.info(localDir.getAbsolutePath());
				setLocalDir(localDir.getAbsolutePath());
				for (String remoteFileName : remoteFileNames) {
					logger.info(remoteFileName);
					getFile(remoteFileName);
				}
				logger.info(ftp.getReplyString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * @param 服务器上的文件名
	 * 下载到本地目录，在下载前需要设置localDir,否则默认是用户工作目录
	 */
	public File getFile(String fileName) {
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return null;
		}
		// ftp.setControlEncoding("gbk");
		File localDir = new File(getLocalDir());
		if (!localDir.isDirectory()) {
			localDir.mkdirs();
		}
		File _localFile = new File(getLocalDir() + File.separator + fileName);
		if (_localFile.exists() && _localFile.isFile()) {
			if (!_localFile.canWrite()) {
				logger.info("file can not wirte");
				return null;
			}
			_localFile.delete();
		}
		try {
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
			BufferedOutputStream bos = new BufferedOutputStream(buffer);
			fileName = new String(fileName.getBytes("gbk"), "ISO-8859-1");
			String _remoteFile = getRemoteDir() + remoteFileSeparator
					+ fileName;
			logger.debug("_remoteFile:" + _remoteFile);
			if (ftp.retrieveFile(_remoteFile, bos)) {
				BufferedOutputStream fileBuffer = new BufferedOutputStream(
						new FileOutputStream(_localFile));
				bos.flush();
				buffer.writeTo(fileBuffer);
				fileBuffer.flush();
				fileBuffer.close();
			} else {
				logger.info("retrieveFile is failed:");
				logger.info(ftp.getReplyString());
			}
			bos.close();
			if(target!=null&&!StringUtils.isBlank(target.getBackpath())){
				String backFile = target.getBackpath() + remoteFileSeparator
						+ fileName;
				logger.info("备份远程文件："+fileName);
				ftp.rename(_remoteFile, backFile);
			}
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("downloadFile has a exception", e);
			return null;
		}
		return _localFile;
	}

	public FTPClient getFtpClient() {
		logger.debug("getFtpClient");
		if (!checkFtpStatu(ftpClient)) {
			try {
				logger.info("重新连接FTP");
				ftpClient = FTPUtils.loginFtp(target.getIp(),target.getUsername(),target.getPassword());
			} catch (IOException e) {
				logger.error("获取FTP连接出错", e);
			}
		}
		return ftpClient;
	}

	public String getLocalDir() {
		return localDir;
	}

	public String getRemoteDir() {
		return remoteDir;
	}

	public Set<File> scanDir() {
		return scanDir(getRemoteDir());
	}

	public Set<File> scanDir(String dir) {
		return scanDir(dir, "txt");
	}

	public Set<File> scanDir(String dir, String fileType) {
		Set<File> remoteFiles = new TreeSet<File>();
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return remoteFiles;
		}
		if (dir == null || StringUtils.isBlank(dir)) {
			logger.info("The directory is not a valid directory");
			return remoteFiles;
		}
		try {
			logger.info("开始扫描目录" + HOME_WORK + remoteFileSeparator
					+ dir + "....");
			FTPFile[] ftpFiles = ftp.listFiles(dir);
			logger.info("扫描到 " + ftpFiles.length + "个文件");
			File localDir = new File(getLocalDir());
			if (!localDir.exists()) {
				localDir.mkdirs();
			}
			setLocalDir(localDir.getAbsolutePath());
			for (FTPFile ftpFile : ftpFiles) {
				String fileName = ftpFile.getName();
				logger.debug("fileName is :" + fileName);
				if (ftpFile.isFile()) {
					if (StringUtils.isBlank(fileType)
							|| StringUtils.endsWithIgnoreCase(fileName, ".*")) {
						File localFile = getFile(fileName);
						remoteFiles.add(localFile);
						continue;
					}
					if (StringUtils
							.endsWithIgnoreCase(fileName, "." + fileType)) {
						File localFile = getFile(fileName);
						remoteFiles.add(localFile);
					}
				}
			}
			logger.info(ftp.getReplyString());
		} catch (Exception e) {
			logger.error("list file error:", e);
			e.printStackTrace();
		}
		return remoteFiles;
	}

	public void setLocalDir(String localDir) {
		this.localDir = localDir;
	}

	public String getRemoteFileSeparator() {
		return this.remoteFileSeparator;
	}

	/**
	 * 获取ftp的主目录
	 */
	public String getHomeWork() {
		return this.HOME_WORK;
	}

	public void setRemoteDir(String remoteDir) {
		this.remoteDir = remoteDir;
	}

	/**
	 * 复制远程文件 2011-8-23 pugang
	 */
	public boolean renameFile(String from, String to) {
		if (StringUtils.isBlank(from)) {
			logger.error("Trom file name " + from + "is invaild!");
			return false;
		}
		if (StringUtils.isBlank(to)) {
			logger.error("To file name " + to + "is invaild!");
			return false;
		}
		FTPClient ftp = getFtpClient();
		if (checkFtpStatu(ftp)) {
			try {
				boolean result = ftp.rename(from, to);
				return result;
			} catch (IOException e) {
				logger.error("rename file error", e);
				e.printStackTrace();
				return false;
			} finally {
				logger.info(ftp.getReplyString());
			}
		}
		return false;
	}

	/**
	 * 删除远程文件
	 * 
	 * @param fileName
	 * @return
	 */
	public boolean deleteFile(String fileName) {
		if (StringUtils.isBlank(fileName)) {
			logger.error("Trom file name " + fileName + "is invaild!");
			return false;
		}
		FTPClient ftp = getFtpClient();
		if (checkFtpStatu(ftp)) {
			try {
				boolean result = ftp.deleteFile(fileName);
				return result;
			} catch (IOException e) {
				logger.error("delete file error", e);
				e.printStackTrace();
				return false;
			} finally {
				logger.error(ftp.getReplyString());
			}
		}
		return false;
	}

	public boolean uploadFile(String fileName) {
		logger.debug("开始上传文件："+fileName);
		FTPClient ftp = getFtpClient();
		if (!checkFtpStatu(ftp)) {
			logger.error("ftp can not be available");
			ftp = getFtpClient();
			if (ftp == null) {
				logger.error("ftp reconnect failed");
				return false;
			}
		}
		File localDir = new File(getLocalDir());
		if (!localDir.isDirectory() || !localDir.exists()) {
			logger.error("The directory " + getLocalDir() + " is not exists");
			return false;
		}
		File _localFile = new File(getLocalDir() + File.separator + fileName);
		if (!_localFile.canRead()) {
			logger.info("file " + _localFile.getAbsolutePath()
					+ " can not be read");
			return false;
		}
		if (!_localFile.exists() || !_localFile.isFile()) {
			logger.info(_localFile.getAbsolutePath() + " is not a file");
			return false;
		}
		try {
			// logger.debug("local req file:"+_localFile);
			String remoteFileName = getRemoteDir() + remoteFileSeparator
					+ fileName;
			logger.debug("remoteFileName:" + remoteFileName);
			InputStream ins = new BufferedInputStream(new FileInputStream(
					_localFile));
			// TODO 有待优化字符编码
			remoteFileName = new String(remoteFileName.getBytes("gbk"),
					"iso-8859-1");
			ftp.storeFile(remoteFileName, ins);
			ins.close();
		} catch (Exception e) {
			logger.error("write file error:", e);
			// e.printStackTrace();
			return false;
		}
		return true;
	}

	private boolean checkFtpStatu(FTPClient ftp) {
		try {
			if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
				logger.error("ftp can not be available");
				return false;
			}
			// 测试连接是否可用，如果不可用则产生异常
			logger.debug("checkFtpStatu");
			ftp.list();
			logger.debug("FtpStatu ok");
		} catch (Exception e) {
			logger.error("ftp can not be available", e);
			return false;
		}
		return true;
	}

	

}
